home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DJLSR106.ARJ / STRING.CC < prev    next >
C/C++ Source or Header  |  1992-03-30  |  29KB  |  1,324 lines

  1. /* 
  2. Copyright (C) 1988 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. /* 
  19.   String class implementation
  20.  */
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation "_String.h"
  24. #endif
  25. #include <_String.h>
  26. #include <std.h>
  27. #include <ctype.h>
  28. #include <values.h>
  29. #include <new.h>
  30. #include <builtin.h>
  31.  
  32. // extern "C" {
  33. #include <regex.h>
  34. // }
  35.  
  36. void String::error(const char* msg) const
  37. {
  38.   (*lib_error_handler)("String", msg);
  39. }
  40.  
  41. String::operator const char*() const
  42.   return (const char*)chars();
  43. }
  44.  
  45. //  globals
  46.  
  47. StrRep  _nilStrRep = { 0, 1, { 0 } }; // nil strings point here
  48. String _nilString;               // nil SubStrings point here
  49.  
  50.  
  51.  
  52.  
  53. /*
  54.  the following inline fcts are specially designed to work
  55.  in support of String classes, and are not meant as generic replacements
  56.  for libc "str" functions.
  57.  
  58.  inline copy fcts -  I like left-to-right from->to arguments.
  59.  all versions assume that `to' argument is non-null
  60.  
  61.  These are worth doing inline, rather than through calls because,
  62.  via procedural integration, adjacent copy calls can be smushed
  63.  together by the optimizer.
  64. */
  65.  
  66. // copy n bytes
  67. inline static void ncopy(const char* from, char* to, int n)
  68. {
  69.   if (from != to) while (--n >= 0) *to++ = *from++;
  70. }
  71.  
  72. // copy n bytes, null-terminate
  73. inline static void ncopy0(const char* from, char* to, int n)
  74. {
  75.   if (from != to) 
  76.   {
  77.     while (--n >= 0) *to++ = *from++;
  78.     *to = 0;
  79.   }
  80.   else
  81.     to[n] = 0;
  82. }
  83.  
  84. // copy until null
  85. inline static void scopy(const char* from, char* to)
  86. {
  87.   if (from != 0) while((*to++ = *from++) != 0);
  88. }
  89.  
  90. // copy right-to-left
  91. inline static void revcopy(const char* from, char* to, short n)
  92. {
  93.   if (from != 0) while (--n >= 0) *to-- = *from--;
  94. }
  95.  
  96.  
  97. inline static int slen(const char* t) // inline  strlen
  98. {
  99.   if (t == 0)
  100.     return 0;
  101.   else
  102.   {
  103.     const char* a = t;
  104.     while (*a++ != 0);
  105.     return a - 1 - t;
  106.   }
  107. }
  108.  
  109. // minimum & maximum representable rep size
  110.  
  111. #define MAXStrRep_SIZE   ((1 << (SHORTBITS - 1)) - 1)
  112. #define MINStrRep_SIZE   16
  113.  
  114. #ifndef MALLOC_MIN_OVERHEAD
  115. #define MALLOC_MIN_OVERHEAD  4
  116. #endif
  117.  
  118. // The basic allocation primitive:
  119. // Always round request to something close to a power of two.
  120. // This ensures a bit of padding, which often means that
  121. // concatenations don't have to realloc. Plus it tends to
  122. // be faster when lots of Strings are created and discarded,
  123. // since just about any version of malloc (op new()) will
  124. // be faster when it can reuse identically-sized chunks
  125.  
  126. inline static StrRep* Snew(int newsiz)
  127. {
  128.   unsigned int siz = sizeof(StrRep) + newsiz + MALLOC_MIN_OVERHEAD;
  129.   unsigned int allocsiz = MINStrRep_SIZE;
  130.   while (allocsiz < siz) allocsiz <<= 1;
  131.   allocsiz -= MALLOC_MIN_OVERHEAD;
  132.   if (allocsiz >= MAXStrRep_SIZE)
  133.     (*lib_error_handler)("String", "Requested length out of range");
  134.     
  135.   StrRep* rep = (StrRep *) new char[allocsiz];
  136.   rep->sz = allocsiz - sizeof(StrRep);
  137.   return rep;
  138. }
  139.  
  140. // Do-something-while-allocating routines.
  141.  
  142. // We live with two ways to signify empty Sreps: either the
  143. // null pointer (0) or a pointer to the nilStrRep.
  144.  
  145. // We always signify unknown source lengths (usually when fed a char*)
  146. // via len == -1, in which case it is computed.
  147.  
  148. // allocate, copying src if nonull
  149.  
  150. StrRep* Salloc(StrRep* old, const char* src, int srclen, int newlen)
  151. {
  152.   if (old == &_nilStrRep) old = 0;
  153.   if (srclen < 0) srclen = slen(src);
  154.   if (newlen < srclen) newlen = srclen;
  155.   StrRep* rep;
  156.   if (old == 0 || newlen > old->sz)
  157.     rep = Snew(newlen);
  158.   else
  159.     rep = old;
  160.  
  161.   rep->len = newlen;
  162.   ncopy0(src, rep->s, srclen);
  163.  
  164.   if (old != rep && old != 0) delete old;
  165.  
  166.   return rep;
  167. }
  168.  
  169. // reallocate: Given the initial allocation scheme, it will
  170. // generally be faster in the long run to get new space & copy
  171. // than to call realloc
  172.  
  173. StrRep* Sresize(StrRep* old, int newlen)
  174. {
  175.   if (old == &_nilStrRep) old = 0;
  176.   StrRep* rep;
  177.   if (old == 0)
  178.     rep = Snew(newlen);
  179.   else if (newlen > old->sz)
  180.   {
  181.     rep = Snew(newlen);
  182.     ncopy0(old->s, rep->s, old->len);
  183.     delete old;
  184.   }
  185.   else
  186.     rep = old;
  187.  
  188.   rep->len = newlen;
  189.  
  190.   return rep;
  191. }
  192.  
  193. // like allocate, but we know that src is a StrRep
  194.  
  195. StrRep* Scopy(StrRep* old, StrRep* s)
  196. {
  197.   if (old == &_nilStrRep) old = 0;
  198.   if (s == &_nilStrRep) s = 0;
  199.   if (old == s) 
  200.     return (old == 0)? &_nilStrRep : old;
  201.   else if (s == 0)
  202.   {
  203.     old->s[0] = 0;
  204.     old->len = 0;
  205.     return old;
  206.   }
  207.   else 
  208.   {
  209.     StrRep* rep;
  210.     int newlen = s->len;
  211.     if (old == 0 || newlen > old->sz)
  212.     {
  213.       if (old != 0) delete old;
  214.       rep = Snew(newlen);
  215.     }
  216.     else
  217.       rep = old;
  218.     rep->len = newlen;
  219.     ncopy0(s->s, rep->s, newlen);
  220.     return rep;
  221.   }
  222. }
  223.  
  224. // allocate & concatenate
  225.  
  226. StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen)
  227. {
  228.   if (old == &_nilStrRep) old = 0;
  229.   if (srclen < 0) srclen = slen(s);
  230.   if (tlen < 0) tlen = slen(t);
  231.   int newlen = srclen + tlen;
  232.   StrRep* rep;
  233.  
  234.   if (old == 0 || newlen > old->sz || 
  235.       (t >= old->s && t < &(old->s[old->len]))) // beware of aliasing
  236.     rep = Snew(newlen);
  237.   else
  238.     rep = old;
  239.  
  240.   rep->len = newlen;
  241.  
  242.   ncopy(s, rep->s, srclen);
  243.   ncopy0(t, &(rep->s[srclen]), tlen);
  244.  
  245.   if (old != rep && old != 0) delete old;
  246.  
  247.   return rep;
  248. }
  249.  
  250. // double-concatenate
  251.  
  252. StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen,
  253.              const char* u, int ulen)
  254. {
  255.   if (old == &_nilStrRep) old = 0;
  256.   if (srclen < 0) srclen = slen(s);
  257.   if (tlen < 0) tlen = slen(t);
  258.   if (ulen < 0) ulen = slen(u);
  259.   int newlen = srclen + tlen + ulen;
  260.   StrRep* rep;
  261.   if (old == 0 || newlen > old->sz || 
  262.       (t >= old->s && t < &(old->s[old->len])) ||
  263.       (u >= old->s && u < &(old->s[old->len])))
  264.     rep = Snew(newlen);
  265.   else
  266.     rep = old;
  267.  
  268.   rep->len = newlen;
  269.  
  270.   ncopy(s, rep->s, srclen);
  271.   ncopy(t, &(rep->s[srclen]), tlen);
  272.   ncopy0(u, &(rep->s[srclen+tlen]), ulen);
  273.  
  274.   if (old != rep && old != 0) delete old;
  275.  
  276.   return rep;
  277. }
  278.  
  279. // like cat, but we know that new stuff goes in the front of existing rep
  280.  
  281. StrRep* Sprepend(StrRep* old, const char* t, int tlen)
  282. {
  283.   char* s;
  284.   int srclen;
  285.   if (old == &_nilStrRep || old == 0)
  286.   {
  287.     s = 0; old = 0; srclen = 0;
  288.   }
  289.   else
  290.   {
  291.     s = old->s; srclen = old->len;
  292.   }
  293.   if (tlen < 0) tlen = slen(t);
  294.   int newlen = srclen + tlen;
  295.   StrRep* rep;
  296.   if (old == 0 || newlen > old->sz || 
  297.       (t >= old->s && t < &(old->s[old->len])))
  298.     rep = Snew(newlen);
  299.   else
  300.     rep = old;
  301.  
  302.   rep->len = newlen;
  303.  
  304.   revcopy(&(s[srclen]), &(rep->s[newlen]), srclen+1);
  305.   ncopy(t, rep->s, tlen);
  306.  
  307.   if (old != rep && old != 0) delete old;
  308.  
  309.   return rep;
  310. }
  311.  
  312.  
  313. // string compare: first argument is known to be non-null
  314.  
  315. inline static int scmp(const char* a, const char* b)
  316. {
  317.   if (b == 0)
  318.     return *a != 0;
  319.   else
  320.   {
  321.     signed char diff = 0;
  322.     while ((diff = *a - *b++) == 0 && *a++ != 0);
  323.     return diff;
  324.   }
  325. }
  326.  
  327.  
  328. inline static int ncmp(const char* a, int al, const char* b, int bl)
  329. {
  330.   int n = (al <= bl)? al : bl;
  331.   signed char diff;
  332.   while (n-- > 0) if ((diff = *a++ - *b++) != 0) return diff;
  333.   return al - bl;
  334. }
  335.  
  336. int fcompare(const String& x, const String& y)
  337. {
  338.   const char* a = x.chars();
  339.   const char* b = y.chars();
  340.   int al = x.length();
  341.   int bl = y.length();
  342.   int n = (al <= bl)? al : bl;
  343.   signed char diff = 0;
  344.   while (n-- > 0)
  345.   {
  346.     char ac = *a++;
  347.     char bc = *b++;
  348.     if ((diff = ac - bc) != 0)
  349.     {
  350.       if (ac >= 'a' && ac <= 'z')
  351.         ac = ac - 'a' + 'A';
  352.       if (bc >= 'a' && bc <= 'z')
  353.         bc = bc - 'a' + 'A';
  354.       if ((diff = ac - bc) != 0)
  355.         return diff;
  356.     }
  357.   }
  358.   return al - bl;
  359. }
  360.  
  361. // these are not inline, but pull in the above inlines, so are 
  362. // pretty fast
  363.  
  364. int compare(const String& x, const char* b)
  365. {
  366.   return scmp(x.chars(), b);
  367. }
  368.  
  369. int compare(const String& x, const String& y)
  370. {
  371.   return scmp(x.chars(), y.chars());
  372. }
  373.  
  374. int compare(const String& x, const SubString& y)
  375. {
  376.   return ncmp(x.chars(), x.length(), y.chars(), y.length());
  377. }
  378.  
  379. int compare(const SubString& x, const String& y)
  380. {
  381.   return ncmp(x.chars(), x.length(), y.chars(), y.length());
  382. }
  383.  
  384. int compare(const SubString& x, const SubString& y)
  385. {
  386.   return ncmp(x.chars(), x.length(), y.chars(), y.length());
  387. }
  388.  
  389. int compare(const SubString& x, const char* b)
  390. {
  391.   if (b == 0)
  392.     return x.length();
  393.   else
  394.   {
  395.     const char* a = x.chars();
  396.     int n = x.length();
  397.     signed char diff;
  398.     while (n-- > 0) if ((diff = *a++ - *b++) != 0) return diff;
  399.     return (*b == 0) ? 0 : -1;
  400.   }
  401. }
  402.  
  403. /*
  404.  index fcts
  405. */
  406.  
  407. int String::search(int start, int sl, char c) const
  408. {
  409.   const char* s = chars();
  410.   if (sl > 0)
  411.   {
  412.     if (start >= 0)
  413.     {
  414.       const char* a = &(s[start]);
  415.       const char* lasta = &(s[sl]);
  416.       while (a < lasta) if (*a++ == c) return --a - s;
  417.     }
  418.     else
  419.     {
  420.       const char* a = &(s[sl + start + 1]);
  421.       while (--a >= s) if (*a == c) return a - s;
  422.     }
  423.   }
  424.   return -1;
  425. }
  426.  
  427. int String::search(int start, int sl, const char* t, int tl) const
  428. {
  429.   const char* s = chars();
  430.   if (tl < 0) tl = slen(t);
  431.   if (sl > 0 && tl > 0)
  432.   {
  433.     if (start >= 0)
  434.     {
  435.       const char* lasts = &(s[sl - tl]);
  436.       const char* lastt = &(t[tl]);
  437.       const char* p = &(s[start]);
  438.  
  439.       while (p <= lasts)
  440.       {
  441.         const char* x = p++;
  442.         const char* y = t;
  443.         while (*x++ == *y++) if (y >= lastt) return --p - s;
  444.       }
  445.     }
  446.     else
  447.     {
  448.       const char* firsts = &(s[tl - 1]);
  449.       const char* lastt =  &(t[tl - 1]);
  450.       const char* p = &(s[sl + start + 1]); 
  451.  
  452.       while (--p >= firsts)
  453.       {
  454.         const char* x = p;
  455.         const char* y = lastt;
  456.         while (*x-- == *y--) if (y < t) return ++x - s;
  457.       }
  458.     }
  459.   }
  460.   return -1;
  461. }
  462.  
  463. int String::match(int start, int sl, int exact, const char* t, int tl) const
  464. {
  465.   if (tl < 0) tl = slen(t);
  466.  
  467.   if (start < 0)
  468.   {
  469.     start = sl + start - tl + 1;
  470.     if (start < 0 || (exact && start != 0))
  471.       return -1;
  472.   }
  473.   else if (exact && sl - start != tl)
  474.     return -1;
  475.  
  476.   if (sl == 0 || tl == 0 || sl - start < tl || start >= sl)
  477.     return -1;
  478.  
  479.   int n = tl;
  480.   const char* s = &(rep->s[start]);
  481.   while (--n >= 0) if (*s++ != *t++) return -1;
  482.   return tl;
  483. }
  484.  
  485. void SubString::assign(StrRep* ysrc, const char* ys, int ylen)
  486. {
  487.   if (&S == &_nilString) return;
  488.  
  489.   if (ylen < 0) ylen = slen(ys);
  490.   StrRep* targ = S.rep;
  491.   int sl = targ->len - len + ylen;
  492.  
  493.   if (ysrc == targ || sl >= targ->sz)
  494.   {
  495.     StrRep* oldtarg = targ;
  496.     targ = Sresize(0, sl);
  497.     ncopy(oldtarg->s, targ->s, pos);
  498.     ncopy(ys, &(targ->s[pos]), ylen);
  499.     scopy(&(oldtarg->s[pos + len]), &(targ->s[pos + ylen]));
  500.     delete oldtarg;
  501.   }
  502.   else if (len == ylen)
  503.     ncopy(ys, &(targ->s[pos]), len);
  504.   else if (ylen < len)
  505.   {
  506.     ncopy(ys, &(targ->s[pos]), ylen);
  507.     scopy(&(targ->s[pos + len]), &(targ->s[pos + ylen]));
  508.   }
  509.   else
  510.   {
  511.     revcopy(&(targ->s[targ->len]), &(targ->s[sl]), targ->len-pos-len +1);
  512.     ncopy(ys, &(targ->s[pos]), ylen);
  513.   }
  514.   targ->len = sl;
  515.   S.rep = targ;
  516. }
  517.  
  518.  
  519.  
  520. /*
  521.  * substitution
  522.  */
  523.  
  524.  
  525. int String::_gsub(const char* pat, int pl, const char* r, int rl)
  526. {
  527.   int nmatches = 0;
  528.   if (pl < 0) pl = slen(pat);
  529.   if (rl < 0) rl = slen(r);
  530.   int sl = length();
  531.   if (sl <= 0 || pl <= 0 || sl < pl)
  532.     return nmatches;
  533.   
  534.   const char* s = chars();
  535.  
  536.   // prepare to make new rep
  537.   StrRep* nrep = 0;
  538.   int nsz = 0;
  539.   char* x = 0;
  540.  
  541.   int si = 0;
  542.   int xi = 0;
  543.   int remaining = sl;
  544.  
  545.   while (remaining >= pl)
  546.   {
  547.     int pos = search(si, sl, pat, pl);
  548.     if (pos < 0)
  549.       break;
  550.     else
  551.     {
  552.       ++nmatches;
  553.       int mustfit = xi + remaining + rl - pl;
  554.       if (mustfit >= nsz)
  555.       {
  556.         if (nrep != 0) nrep->len = xi;
  557.         nrep = Sresize(nrep, mustfit);
  558.         nsz = nrep->sz;
  559.         x = nrep->s;
  560.       }
  561.       pos -= si;
  562.       ncopy(&(s[si]), &(x[xi]), pos);
  563.       ncopy(r, &(x[xi + pos]), rl);
  564.       si += pos + pl;
  565.       remaining -= pos + pl;
  566.       xi += pos + rl;
  567.     }
  568.   }
  569.  
  570.   if (nrep == 0)
  571.   {
  572.     if (nmatches == 0)
  573.       return nmatches;
  574.     else
  575.       nrep = Sresize(nrep, xi+remaining);
  576.   }
  577.  
  578.   ncopy0(&(s[si]), &(x[xi]), remaining);
  579.   nrep->len = xi + remaining;
  580.  
  581.   if (nrep->len <= rep->sz)   // fit back in if possible
  582.   {
  583.     rep->len = nrep->len;
  584.     ncopy0(nrep->s, rep->s, rep->len);
  585.     delete(nrep);
  586.   }
  587.   else
  588.   {
  589.     delete(rep);
  590.     rep = nrep;
  591.   }
  592.   return nmatches;
  593. }
  594.  
  595. int String::_gsub(const Regex& pat, const char* r, int rl)
  596. {
  597.   int nmatches = 0;
  598.   int sl = length();
  599.   if (sl <= 0)
  600.     return nmatches;
  601.  
  602.   if (rl < 0) rl = slen(r);
  603.  
  604.   const char* s = chars();
  605.  
  606.   StrRep* nrep = 0;
  607.   int nsz = 0;
  608.  
  609.   char* x = 0;
  610.  
  611.   int si = 0;
  612.   int xi = 0;
  613.   int remaining = sl;
  614.   int  pos, pl = 0;                  // how long is a regular expression?
  615.  
  616.   while (remaining > 0)
  617.   {
  618.     pos = pat.search(s, sl, pl, si); // unlike string search, the pos returned here is absolute
  619.     if (pos < 0 || pl <= 0)
  620.       break;
  621.     else
  622.     {
  623.       ++nmatches;
  624.       int mustfit = xi + remaining + rl - pl;
  625.       if (mustfit >= nsz)
  626.       {
  627.         if (nrep != 0) nrep->len = xi;
  628.         nrep = Sresize(nrep, mustfit);
  629.         x = nrep->s;
  630.         nsz = nrep->sz;
  631.       }
  632.       pos -= si;
  633.       ncopy(&(s[si]), &(x[xi]), pos);
  634.       ncopy(r, &(x[xi + pos]), rl);
  635.       si += pos + pl;
  636.       remaining -= pos + pl;
  637.       xi += pos + rl;
  638.     }
  639.   }
  640.  
  641.   if (nrep == 0)
  642.   {
  643.     if (nmatches == 0)
  644.       return nmatches;
  645.     else
  646.       nrep = Sresize(nrep, xi+remaining);
  647.   }
  648.  
  649.   ncopy0(&(s[si]), &(x[xi]), remaining);
  650.   nrep->len = xi + remaining;
  651.  
  652.   if (nrep->len <= rep->sz)   // fit back in if possible
  653.   {
  654.     rep->len = nrep->len;
  655.     ncopy0(nrep->s, rep->s, rep->len);
  656.     delete(nrep);
  657.   }
  658.   else
  659.   {
  660.     delete(rep);
  661.     rep = nrep;
  662.   }
  663.   return nmatches;
  664. }
  665.  
  666.  
  667. /*
  668.  * deletion
  669.  */
  670.  
  671. void String::del(int pos, int len)
  672. {
  673.   if (pos < 0 || len <= 0 || (unsigned)(pos + len) > length()) return;
  674.   int nlen = length() - len;
  675.   int first = pos + len;
  676.   ncopy0(&(rep->s[first]), &(rep->s[pos]), length() - first);
  677.   rep->len = nlen;
  678. }
  679.  
  680. void String::del(const Regex& r, int startpos)
  681. {
  682.   int mlen;
  683.   int first = r.search(chars(), length(), mlen, startpos);
  684.   del(first, mlen);
  685. }
  686.  
  687. void String::del(const char* t, int startpos)
  688. {
  689.   int tlen = slen(t);
  690.   int p = search(startpos, length(), t, tlen);
  691.   del(p, tlen);
  692. }
  693.  
  694. void String::del(const String& y, int startpos)
  695. {
  696.   del(search(startpos, length(), y.chars(), y.length()), y.length());
  697. }
  698.  
  699. void String::del(const SubString& y, int startpos)
  700. {
  701.   del(search(startpos, length(), y.chars(), y.length()), y.length());
  702. }
  703.  
  704. void String::del(char c, int startpos)
  705. {
  706.   del(search(startpos, length(), c), 1);
  707. }
  708.  
  709. /*
  710.  * substring extraction
  711.  */
  712.  
  713.  
  714. SubString String::at(int first, int len)
  715. {
  716.   return _substr(first, len);
  717. }
  718.  
  719. SubString String::operator() (int first, int len)
  720. {
  721.   return _substr(first, len);
  722. }
  723.  
  724. SubString String::before(int pos)
  725. {
  726.   return _substr(0, pos);
  727. }
  728.  
  729. SubString String::through(int pos)
  730. {
  731.   return _substr(0, pos+1);
  732. }
  733.  
  734. SubString String::after(int pos)
  735. {
  736.   return _substr(pos + 1, length() - (pos + 1));
  737. }
  738.  
  739. SubString String::from(int pos)
  740. {
  741.   return _substr(pos, length() - pos);
  742. }
  743.  
  744. SubString String::at(const String& y, int startpos)
  745. {
  746.   int first = search(startpos, length(), y.chars(), y.length());
  747.   return _substr(first,  y.length());
  748. }
  749.  
  750. SubString String::at(const SubString& y, int startpos)
  751. {
  752.   int first = search(startpos, length(), y.chars(), y.length());
  753.   return _substr(first, y.length());
  754. }
  755.  
  756. SubString String::at(const Regex& r, int startpos)
  757. {
  758.   int mlen;
  759.   int first = r.search(chars(), length(), mlen, startpos);
  760.   return _substr(first, mlen);
  761. }
  762.  
  763. SubString String::at(const char* t, int startpos)
  764. {
  765.   int tlen = slen(t);
  766.   int first = search(startpos, length(), t, tlen);
  767.   return _substr(first, tlen);
  768. }
  769.  
  770. SubString String::at(char c, int startpos)
  771. {
  772.   int first = search(startpos, length(), c);
  773.   return _substr(first, 1);
  774. }
  775.  
  776. SubString String::before(const String& y, int startpos)
  777. {
  778.   int last = search(startpos, length(), y.chars(), y.length());
  779.   return _substr(0, last);
  780. }
  781.  
  782. SubString String::before(const SubString& y, int startpos)
  783. {
  784.   int last = search(startpos, length(), y.chars(), y.length());
  785.   return _substr(0, last);
  786. }
  787.  
  788. SubString String::before(const Regex& r, int startpos)
  789. {
  790.   int mlen;
  791.   int first = r.search(chars(), length(), mlen, startpos);
  792.   return _substr(0, first);
  793. }
  794.  
  795. SubString String::before(char c, int startpos)
  796. {
  797.   int last = search(startpos, length(), c);
  798.   return _substr(0, last);
  799. }
  800.  
  801. SubString String::before(const char* t, int startpos)
  802. {
  803.   int tlen = slen(t);
  804.   int last = search(startpos, length(), t, tlen);
  805.   return _substr(0, last);
  806. }
  807.  
  808. SubString String::through(const String& y, int startpos)
  809. {
  810.   int last = search(startpos, length(), y.chars(), y.length());
  811.   if (last >= 0) last += y.length();
  812.   return _substr(0, last);
  813. }
  814.  
  815. SubString String::through(const SubString& y, int startpos)
  816. {
  817.   int last = search(startpos, length(), y.chars(), y.length());
  818.   if (last >= 0) last += y.length();
  819.   return _substr(0, last);
  820. }
  821.  
  822. SubString String::through(const Regex& r, int startpos)
  823. {
  824.   int mlen;
  825.   int first = r.search(chars(), length(), mlen, startpos);
  826.   if (first >= 0) first += mlen;
  827.   return _substr(0, first);
  828. }
  829.  
  830. SubString String::through(char c, int startpos)
  831. {
  832.   int last = search(startpos, length(), c);
  833.   if (last >= 0) last += 1;
  834.   return _substr(0, last);
  835. }
  836.  
  837. SubString String::through(const char* t, int startpos)
  838. {
  839.   int tlen = slen(t);
  840.   int last = search(startpos, length(), t, tlen);
  841.   if (last >= 0) last += tlen;
  842.   return _substr(0, last);
  843. }
  844.  
  845. SubString String::after(const String& y, int startpos)
  846. {
  847.   int first = search(startpos, length(), y.chars(), y.length());
  848.   if (first >= 0) first += y.length();
  849.   return _substr(first, length() - first);
  850. }
  851.  
  852. SubString String::after(const SubString& y, int startpos)
  853. {
  854.   int first = search(startpos, length(), y.chars(), y.length());
  855.   if (first >= 0) first += y.length();
  856.   return _substr(first, length() - first);
  857. }
  858.  
  859. SubString String::after(char c, int startpos)
  860. {
  861.   int first = search(startpos, length(), c);
  862.   if (first >= 0) first += 1;
  863.   return _substr(first, length() - first);
  864. }
  865.  
  866. SubString String::after(const Regex& r, int startpos)
  867. {
  868.   int mlen;
  869.   int first = r.search(chars(), length(), mlen, startpos);
  870.   if (first >= 0) first += mlen;
  871.   return _substr(first, length() - first);
  872. }
  873.  
  874. SubString String::after(const char* t, int startpos)
  875. {
  876.   int tlen = slen(t);
  877.   int first = search(startpos, length(), t, tlen);
  878.   if (first >= 0) first += tlen;
  879.   return _substr(first, length() - first);
  880. }
  881.  
  882. SubString String::from(const String& y, int startpos)
  883. {
  884.   int first = search(startpos, length(), y.chars(), y.length());
  885.   return _substr(first, length() - first);
  886. }
  887.  
  888. SubString String::from(const SubString& y, int startpos)
  889. {
  890.   int first = search(startpos, length(), y.chars(), y.length());
  891.   return _substr(first, length() - first);
  892. }
  893.  
  894. SubString String::from(const Regex& r, int startpos)
  895. {
  896.   int mlen;
  897.   int first = r.search(chars(), length(), mlen, startpos);
  898.   return _substr(first, length() - first);
  899. }
  900.  
  901. SubString String::from(char c, int startpos)
  902. {
  903.   int first = search(startpos, length(), c);
  904.   return _substr(first, length() - first);
  905. }
  906.  
  907. SubString String::from(const char* t, int startpos)
  908. {
  909.   int tlen = slen(t);
  910.   int first = search(startpos, length(), t, tlen);
  911.   return _substr(first, length() - first);
  912. }
  913.  
  914.  
  915.  
  916. /*
  917.  * split/join
  918.  */
  919.  
  920.  
  921. int split(const String& src, String results[], int n, const String& sep)
  922. {
  923.   String x = src;
  924.   const char* s = x.chars();
  925.   int sl = x.length();
  926.   int i = 0;
  927.   int pos = 0;
  928.   while (i < n && pos < sl)
  929.   {
  930.     int p = x.search(pos, sl, sep.chars(), sep.length());
  931.     if (p < 0)
  932.       p = sl;
  933.     results[i].rep = Salloc(results[i].rep, &(s[pos]), p - pos, p - pos);
  934.     i++;
  935.     pos = p + sep.length();
  936.   }
  937.   return i;
  938. }
  939.  
  940. int split(const String& src, String results[], int n, const Regex& r)
  941. {
  942.   String x = src;
  943.   const char* s = x.chars();
  944.   int sl = x.length();
  945.   int i = 0;
  946.   int pos = 0;
  947.   int p, matchlen;
  948.   while (i < n && pos < sl)
  949.   {
  950.     p = r.search(s, sl, matchlen, pos);
  951.     if (p < 0)
  952.       p = sl;
  953.     results[i].rep = Salloc(results[i].rep, &(s[pos]), p - pos, p - pos);
  954.     i++;
  955.     pos = p + matchlen;
  956.   }
  957.   return i;
  958. }
  959.  
  960.  
  961. #if defined(__GNUG__) && !defined(NO_NRV)
  962.  
  963. String join(String src[], int n, const String& separator) return x;
  964. {
  965.   String sep = separator;
  966.   int xlen = 0;
  967.   for (int i = 0; i < n; ++i)
  968.     xlen += src[i].length();
  969.   xlen += (n - 1) * sep.length();
  970.  
  971.   x.alloc(xlen);
  972.  
  973.   int j = 0;
  974.   
  975.   for (i = 0; i < n - 1; ++i)
  976.   {
  977.     ncopy(src[i].chars(), &(x.rep->s[j]), src[i].length());
  978.     j += src[i].length();
  979.     ncopy(sep.chars(), &(x.rep->s[j]), sep.length());
  980.     j += sep.length();
  981.   }
  982.   ncopy0(src[i].chars(), &(x.rep->s[j]), src[i].length());
  983. }
  984.  
  985. #else
  986.  
  987. String join(String src[], int n, const String& separator)
  988. {
  989.   String x;
  990.   String sep = separator;
  991.   int xlen = 0;
  992.   for (int i = 0; i < n; ++i)
  993.     xlen += src[i].length();
  994.   xlen += (n - 1) * sep.length();
  995.  
  996.   x.alloc(xlen);
  997.  
  998.   int j = 0;
  999.   
  1000.   for (i = 0; i < n - 1; ++i)
  1001.   {
  1002.     ncopy(src[i].chars(), &(x.rep->s[j]), src[i].length());
  1003.     j += src[i].length();
  1004.     ncopy(sep.chars(), &(x.rep->s[j]), sep.length());
  1005.     j += sep.length();
  1006.   }
  1007.   ncopy0(src[i].chars(), &(x.rep->s[j]), src[i].length());
  1008.   return x;
  1009. }
  1010.  
  1011. #endif
  1012.   
  1013. /*
  1014.  misc
  1015. */
  1016.  
  1017.     
  1018. StrRep* Sreverse(StrRep* src, StrRep* dest)
  1019. {
  1020.   int n = src->len;
  1021.   if (src != dest)
  1022.     dest = Salloc(dest, src->s, n, n);
  1023.   if (n > 0)
  1024.   {
  1025.     char* a = dest->s;
  1026.     char* b = &(a[n - 1]);
  1027.     while (a < b)
  1028.     {
  1029.       char t = *a;
  1030.       *a++ = *b;
  1031.       *b-- = t;
  1032.     }
  1033.   }
  1034.   return dest;
  1035. }
  1036.  
  1037.  
  1038. StrRep* Supcase(StrRep* src, StrRep* dest)
  1039. {
  1040.   int n = src->len;
  1041.   if (src != dest) dest = Salloc(dest, src->s, n, n);
  1042.   char* p = dest->s;
  1043.   char* e = &(p[n]);
  1044.   for (; p < e; ++p) if (islower(*p)) *p = toupper(*p);
  1045.   return dest;
  1046. }
  1047.  
  1048. StrRep* Sdowncase(StrRep* src, StrRep* dest)
  1049. {
  1050.   int n = src->len;
  1051.   if (src != dest) dest = Salloc(dest, src->s, n, n);
  1052.   char* p = dest->s;
  1053.   char* e = &(p[n]);
  1054.   for (; p < e; ++p) if (isupper(*p)) *p = tolower(*p);
  1055.   return dest;
  1056. }
  1057.  
  1058. StrRep* Scapitalize(StrRep* src, StrRep* dest)
  1059. {
  1060.   int n = src->len;
  1061.   if (src != dest) dest = Salloc(dest, src->s, n, n);
  1062.  
  1063.   char* p = dest->s;
  1064.   char* e = &(p[n]);
  1065.   for (; p < e; ++p)
  1066.   {
  1067.     int at_word;
  1068.     if (at_word = islower(*p))
  1069.       *p = toupper(*p);
  1070.     else 
  1071.       at_word = isupper(*p) || isdigit(*p);
  1072.  
  1073.     if (at_word)
  1074.     {
  1075.       while (++p < e)
  1076.       {
  1077.         if (isupper(*p))
  1078.           *p = tolower(*p);
  1079.         else if (!islower(*p) && !isdigit(*p))
  1080.           break;
  1081.       }
  1082.     }
  1083.   }
  1084.   return dest;
  1085. }
  1086.  
  1087. #if defined(__GNUG__) && !defined(NO_NRV)
  1088.  
  1089. String replicate(char c, int n) return w;
  1090. {
  1091.   w.rep = Sresize(w.rep, n);
  1092.   char* p = w.rep->s;
  1093.   while (n-- > 0) *p++ = c;
  1094.   *p = 0;
  1095. }
  1096.  
  1097. String replicate(const String& y, int n) return w
  1098. {
  1099.   int len = y.length();
  1100.   w.rep = Sresize(w.rep, n * len);
  1101.   char* p = w.rep->s;
  1102.   while (n-- > 0)
  1103.   {
  1104.     ncopy(y.chars(), p, len);
  1105.     p += len;
  1106.   }
  1107.   *p = 0;
  1108. }
  1109.  
  1110. String common_prefix(const String& x, const String& y, int startpos) return r;
  1111. {
  1112.   const char* xchars = x.chars();
  1113.   const char* ychars = y.chars();
  1114.   const char* xs = &(xchars[startpos]);
  1115.   const char* ss = xs;
  1116.   const char* topx = &(xchars[x.length()]);
  1117.   const char* ys = &(ychars[startpos]);
  1118.   const char* topy = &(ychars[y.length()]);
  1119.   for (int l = 0; xs < topx && ys < topy && *xs++ == *ys++; ++l);
  1120.   r.rep = Salloc(r.rep, ss, l, l);
  1121. }
  1122.  
  1123. String common_suffix(const String& x, const String& y, int startpos) return r;
  1124. {
  1125.   const char* xchars = x.chars();
  1126.   const char* ychars = y.chars();
  1127.   const char* xs = &(xchars[x.length() + startpos]);
  1128.   const char* botx = xchars;
  1129.   const char* ys = &(ychars[y.length() + startpos]);
  1130.   const char* boty = ychars;
  1131.   for (int l = 0; xs >= botx && ys >= boty && *xs == *ys ; --xs, --ys, ++l);
  1132.   r.rep = Salloc(r.rep, ++xs, l, l);
  1133. }
  1134.  
  1135. #else
  1136.  
  1137. String replicate(char c, int n)
  1138. {
  1139.   String w;
  1140.   w.rep = Sresize(w.rep, n);
  1141.   char* p = w.rep->s;
  1142.   while (n-- > 0) *p++ = c;
  1143.   *p = 0;
  1144.   return w;
  1145. }
  1146.  
  1147. String replicate(const String& y, int n)
  1148. {
  1149.   String w;
  1150.   int len = y.length();
  1151.   w.rep = Sresize(w.rep, n * len);
  1152.   char* p = w.rep->s;
  1153.   while (n-- > 0)
  1154.   {
  1155.     ncopy(y.chars(), p, len);
  1156.     p += len;
  1157.   }
  1158.   *p = 0;
  1159.   return w;
  1160. }
  1161.  
  1162. String common_prefix(const String& x, const String& y, int startpos)
  1163. {
  1164.   String r;
  1165.   const char* xchars = x.chars();
  1166.   const char* ychars = y.chars();
  1167.   const char* xs = &(xchars[startpos]);
  1168.   const char* ss = xs;
  1169.   const char* topx = &(xchars[x.length()]);
  1170.   const char* ys = &(ychars[startpos]);
  1171.   const char* topy = &(ychars[y.length()]);
  1172.   for (int l = 0; xs < topx && ys < topy && *xs++ == *ys++; ++l);
  1173.   r.rep = Salloc(r.rep, ss, l, l);
  1174.   return r;
  1175. }
  1176.  
  1177. String common_suffix(const String& x, const String& y, int startpos) 
  1178. {
  1179.   String r;
  1180.   const char* xchars = x.chars();
  1181.   const char* ychars = y.chars();
  1182.   const char* xs = &(xchars[x.length() + startpos]);
  1183.   const char* botx = xchars;
  1184.   const char* ys = &(ychars[y.length() + startpos]);
  1185.   const char* boty = ychars;
  1186.   for (int l = 0; xs >= botx && ys >= boty && *xs == *ys ; --xs, --ys, ++l);
  1187.   r.rep = Salloc(r.rep, ++xs, l, l);
  1188.   return r;
  1189. }
  1190.  
  1191. #endif
  1192.  
  1193. // IO
  1194.  
  1195. istream& operator>>(istream& s, String& x)
  1196. {
  1197. #ifdef _OLD_STREAMS
  1198.   if (!s.good())
  1199.   {
  1200.     return s;
  1201.   }
  1202.   s >> ws;
  1203.   if (!s.good())
  1204.   {
  1205.     return s;
  1206.   }
  1207. #else
  1208.   if (!s.ipfx(0))
  1209.   {
  1210.     s.set(ios::failbit); // Redundant if using GNU iostreams.
  1211.     return s;
  1212.   }
  1213. #endif
  1214.   char ch;
  1215.   int i = 0;
  1216.   x.rep = Sresize(x.rep, 20);
  1217.   while (s.get(ch))
  1218.   {
  1219.     if (isspace(ch))
  1220.       break;
  1221.     if (i >= x.rep->sz - 1)
  1222.       x.rep = Sresize(x.rep, i+1);
  1223.     x.rep->s[i++] = ch;
  1224.   }
  1225.   x.rep->s[i] = 0;
  1226.   x.rep->len = i;
  1227.   if(i == 0) s.clear(_bad);
  1228.   return s;
  1229. }
  1230.  
  1231. int readline(istream& s, String& x, char terminator, int discard)
  1232. {
  1233. #ifdef _OLD_STREAMS
  1234.   if (!s.good())
  1235. #else
  1236.   if (!s.ipfx(0))
  1237. #endif
  1238.   {
  1239.     return 0;
  1240.   }
  1241.   char ch;
  1242.   int i = 0;
  1243.   x.rep = Sresize(x.rep, 80);
  1244.   while (s.get(ch))
  1245.   {
  1246.     if (ch != terminator || !discard)
  1247.     {
  1248.       if (i >= x.rep->sz - 1)
  1249.         x.rep = Sresize(x.rep, i+1);
  1250.       x.rep->s[i++] = ch;
  1251.     }
  1252.     if (ch == terminator)
  1253.       break;
  1254.   }
  1255.   x.rep->s[i] = 0;
  1256.   x.rep->len = i;
  1257.   return i;
  1258. }
  1259.  
  1260.  
  1261. ostream& operator<<(ostream& s, const SubString& x)
  1262.   const char* a = x.chars();
  1263.   const char* lasta = &(a[x.length()]);
  1264.   while (a < lasta)
  1265.     s.put(*a++);
  1266.   return(s);
  1267. }
  1268.  
  1269. // from John.Willis@FAS.RI.CMU.EDU
  1270.  
  1271. int String::freq(const SubString& y) const
  1272. {
  1273.   int found = 0;
  1274.   for (unsigned int i = 0; i < length(); i++) 
  1275.     if (match(i,length(),0,y.chars(), y.length())>= 0) found++;
  1276.   return(found);
  1277. }
  1278.  
  1279. int String::freq(const String& y) const
  1280. {
  1281.   int found = 0;
  1282.   for (unsigned int i = 0; i < length(); i++) 
  1283.     if (match(i,length(),0,y.chars(),y.length()) >= 0) found++;
  1284.   return(found);
  1285. }
  1286.  
  1287. int String::freq(const char* t) const
  1288. {
  1289.   int found = 0;
  1290.   for (unsigned int i = 0; i < length(); i++) 
  1291.     if (match(i,length(),0,t) >= 0) found++;
  1292.   return(found);
  1293. }
  1294.  
  1295. int String::freq(char c) const
  1296. {
  1297.   int found = 0;
  1298.   for (unsigned int i = 0; i < length(); i++) 
  1299.     if (match(i,length(),0,&c,1) >= 0) found++;
  1300.   return(found);
  1301. }
  1302.  
  1303.  
  1304. int String::OK() const
  1305. {
  1306.   int v = rep != 0;             // have a rep
  1307.   v &= rep->len <= rep->sz;     // string within bounds
  1308.   v &= rep->s[rep->len] == 0;   // null-terminated
  1309.   if (!v) error("invariant failure");
  1310.   return v;
  1311. }
  1312.  
  1313. int SubString::OK() const
  1314. {
  1315.   int v = S != 0;               // have a String;
  1316.   v &= S.OK();                 // that is legal
  1317.   v &= pos + len >= S.rep->len;// pos and len within bounds
  1318.   if (!v) S.error("SubString invariant failure");
  1319.   return v;
  1320. }
  1321.  
  1322.